package sample;

import flex.messaging.MessageBroker;
import flex.messaging.MessageClient;
import flex.messaging.MessageClientListener;
import flex.messaging.config.ConfigMap;
import flex.messaging.messages.AsyncMessage;
import flex.messaging.services.AbstractBootstrapService;
import flex.messaging.util.UUIDUtils;

public class ShareBoardBootstrapService extends AbstractBootstrapService {
	private static String[] colors = { "red", "green", "blue", "brown",
			"orange" };
	private static int colorsIndex = 0;

	private static synchronized String nextColor() {
		if (colorsIndex >= colors.length)
			colorsIndex = 0;
		return colors[colorsIndex++];
	}

	@Override
	public void initialize(String id, ConfigMap properties) {
		// クライアントの接続・切断を監視するリスナを登録する。
		MessageClient.addMessageClientCreatedListener(new ClientWatcher());
	}

	@Override
	public void start() {
		// なにもしない。
	}

	@Override
	public void stop() {
		// なにもしない。
	}

	class ClientWatcher implements MessageClientListener {
		/**
		 * クライアントが接続したときに呼ばれる。
		 */
		public void messageClientCreated(MessageClient msgClient) {
			String color = nextColor();

			// 線の色を割り当てる。
			(new ColorAllocator(msgClient, color)).start();

			// 新しいユーザが接続したことを通知する。
			String userName = msgClient.getFlexSession().getUserPrincipal()
					.getName();
			notifyOtherClients(msgClient.getDestinationId(), userName
					+ " has joined as " + color + ".");

			System.out.println(userName + " has joined as " + color + ".");

			// 自身をクライアントの切断を監視するリスナとしても登録する。
			msgClient.addMessageClientDestroyedListener(this);
		}

		/**
		 * クライアントが切断したときに呼ばれる。
		 */
		public void messageClientDestroyed(MessageClient msgClient) {
			// ユーザが切断したことを通知する。
			String userName = msgClient.getFlexSession().getUserPrincipal()
					.getName();
			notifyOtherClients(msgClient.getDestinationId(), userName
					+ " has left.");

			System.out.println(userName + " has left.");

			// 明示的にセッションを破棄する。
			msgClient.getFlexSession().timeout();
		}

		/**
		 * 接続中の他クライアントにメッセージを送る。
		 * @param dest 接続先
		 * @param msgText メッセージ
		 */
		private void notifyOtherClients(String dest, String msgText) {
			MessageBroker msgBroker = MessageBroker.getMessageBroker(null);
			AsyncMessage msg = new AsyncMessage();
			msg.setMessageId(UUIDUtils.createUUID());
			msg.setTimestamp(System.currentTimeMillis());
			msg.setDestination(dest);
			msg.setHeader("operation", "log");
			msg.setBody(msgText);
			msgBroker.routeMessageToService(msg, null);
		}
	}

	class ColorAllocator extends Thread {
		private MessageClient client;
		private String color;

		ColorAllocator(MessageClient client, String color) {
			this.client = client;
			this.color = color;
		}

		@Override
		public void run() {
			// メッセージの受信漏れを防ぐため遅延させる。
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
			}
			MessageBroker msgBroker = MessageBroker.getMessageBroker(null);
			AsyncMessage msg = new AsyncMessage();
			msg.setMessageId(UUIDUtils.createUUID());
			msg.setTimestamp(System.currentTimeMillis());
			msg.setClientId(client.getClientId());
			msg.setHeader("operation", "color");
			msg.setBody(color);
			msgBroker.routeMessageToMessageClient(msg, client);
		}
	}
}
